/*
 * @Author: zhuxiaoyi
 * @Date: 2024-01-26 14:52:39
 * @LastEditor: zhuxiaoyi
 * @LastEditTime: 2025-08-27 18:44:29
 * @Description:
 */
import { Provide, App, Inject, Config } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Task } from '../entity/task.entity';
import { Graph } from '../entity/graph.entity';
import { Algorithm } from '../entity/algorithm.entity';
import { Repository, Like } from 'typeorm';
import { Ipage } from '../interface';
import { Application } from '@midwayjs/ws';
import * as childProcess from 'child_process';
import { InjectJob, CronJob } from '@midwayjs/cron';
import { DataSyncCheckerJob } from '../job/sync.job';
import { M1Product } from '../entity/module1.entity';
import { SoilEtResult } from '../entity/detection-results.entity'
import { basename, dirname, extname, parse } from 'path';
import { PromiseService } from '../service/promise.service';
import { promises as fs1 } from 'fs';
import { GraphService } from './graph.service';
import axios from 'axios';
import * as fs from 'fs';
import * as path from 'path';
const archiver = require('archiver');
@Provide()
export class TaskService {
  @InjectEntityModel(Task)
  taskModel: Repository<Task>;

  @InjectEntityModel(Graph)
  GraphModel: Repository<Graph>;

  @InjectEntityModel(Algorithm)
  AlgorithmModel: Repository<Algorithm>;

  @App('webSocket')
  wsApp: Application;

  @InjectJob(DataSyncCheckerJob)
  syncJob: CronJob;

  @Inject()
  promiseService: PromiseService;


  @Inject()
  GraphService: GraphService;

  @Config('matlabExePath')
  matlabExePath;

  @Config('ArcGISPythonURL')
  ArcGISPythonURL;

  @Config('matlabRuntimeParamPath')
  matlabRuntimeParamPath;

  @Config('renbaoBaseURL')
  renbaoBaseURL;

  @InjectEntityModel(M1Product)
  M1ProductModel: Repository<M1Product>;


  @InjectEntityModel(SoilEtResult)
  SoilEtResultModel: Repository<SoilEtResult>;


  //算法任务执行
  async createTask(algorithm: any) {
    try {
      const timestamp = Date.now();
      const taskName = `算法任务_${algorithm.name}_${timestamp}`;
      const task = new Task();
      task.name = taskName;
      task.progress = 0;
      task.type = 1; //算法任务
      task.algorithm = algorithm;
      let savedTask;
      if (algorithm.allowAsync) {
        task.status = 2;
        savedTask = await this.taskModel.save(task);
        await this.executeSwitch(savedTask);
      } else {
        const runTask = await this.taskModel.findOne({
          where: [
            { algorithm: { id: algorithm.id }, status: 2 }
          ],
        });
        if (runTask) {
          task.status = 0;
          task.parameters = algorithm.parameters
          savedTask = await this.taskModel.save(task);
        } else {
          task.status = 2;
          savedTask = await this.taskModel.save(task);
          await this.executeSwitch(savedTask);
        }
      }
      return savedTask;
    } catch (error) {
      console.error('创建任务失败:', error);
      return false;
    }
  }

  async executeSwitch(task) {
    console.log(task.algorithm.executeType)
    switch (task.algorithm.executeType) {
      case 1:
        await this.executeAlgorithm(task);
        break;
      case 2:
        await this.publishTifToGeoServer(task);
        break;
      case 3:
        await this.publishShpFile(task);
        break;
      case 4:
        await this.bindStyleToLayer(task);
        break;
      case 5:
        await this.previewResult(task);
        break;
      case 6:
        await this.pushMPDIResult(task); //MPDI成果推送
        break;
      case 7:
        await this.createBatchCatalogue(task); //预览tif+shp
        break;
      case 8:
        await this.batchTask(task); //批量处理 1.0
      case 9:
        await this.generalBatchTask(task); //通用批处理算法
        break;
      case 10:
        await this.batchCatalogueByDir(task); //批处理目录生成
        break;
      case 11:
        await this.executeMatlabAlgorithm(task); //批处理目录生成
        break;
      case 12:
        await this.executePythonAlgorithm(task);
        break;
      case 13:
        await this.resultBatchPush(task); //土含/蒸散发成果批量推送
        break;
      case 18:
        await this.executeLinuxAlgorithm(task); //土含/蒸散发成果批量推送
        break;
      default:
        break;
    }
  }

  async createTaskByGraph(graph: Graph) {
    try {
      const taskName = `流程任务_${graph.name}`;
      const task = new Task();
      task.name = taskName;
      task.progress = 0;
      task.type = 2; //流程任务
      task.status = 0;
      task.graphId = graph.id
      let savedTask = await this.taskModel.save(task);
      return savedTask;
    } catch (error) {
      console.error('创建任务失败:', error);
      return false;
    }
  }

  async createAsyncTaskByGraph(graph: Graph) {
    try {
      const taskName = `流程任务_${graph.name}`;
      const task = new Task();
      task.name = taskName;
      task.progress = 0;
      task.type = 2; //流程任务
      task.status = 0;
      task.graphId = graph.id;
      task.allowAsync = false;
      let savedTask = await this.taskModel.save(task);
      return savedTask;
    } catch (error) {
      console.error('创建任务失败:', error);
      return false;
    }
  }


  async updateTaskProgress(task: any, status, progress) {
    try {
      task.status = status;
      task.progress = Math.floor(progress);
      await this.taskModel.save(task);
      await this.invoke();
    } catch (error) {
      console.error('更新任务进度失败:', error);
    }
  }

  async executeMatlabAlgorithm(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();

    return new Promise((resolve, reject) => {
      const exePath = task.algorithm.application;
      const parameters = JSON.parse(task.algorithm.parameters);
      const parametersParsed = this.convertJsonArrayToObject(parameters);
      parametersParsed.task_id = (task.id).toString()
      console.log(parametersParsed);

      const now = new Date();
      const timestamp = `${now.getHours()}-${now.getMinutes()}-${now.getSeconds()}`;
      const fileName = `runtime_params_${timestamp}.json`;
      const filePath = path.join(this.matlabRuntimeParamPath, fileName);
      fs.writeFile(filePath, JSON.stringify(parametersParsed, null, 2), (err) => {
        if (err) {
          reject(err);
          return;
        }

        const jsonFilePath = filePath;
        const addpath = path.dirname(exePath);
        const mainFunction = path.basename(exePath, '.m');
        const matlabCommand = `jsonFilePath = '${jsonFilePath}'; addpath('${addpath}'); ${mainFunction}(jsonFilePath); exit`;
        const child = childProcess.spawn(this.matlabExePath, ['-nodisplay', '-nosplash', '-nodesktop', '-r', matlabCommand]);
        let logOutput = ''; // 用于保存日志信息

        // 监听子进程的标准输出
        child.stdout.on('data', data => {
          logOutput += data.toString('utf-8');
          let log = data.toString('utf-8');
          console.log(log); // 输出日志到控制台
        });

        // 监听子进程的标准错误输出
        child.stderr.on('data', data => {
          logOutput += data.toString('utf-8');
          console.error(data.toString('utf-8'));
        });

        // 监听子进程的退出事件
        child.on('exit', async code => {
        });
        this.promiseService.createPromise((task.id).toString()).then(() => {
          console.log('算法执行完成');
          task.status = 1;
          task.progress = 100;
          this.taskModel.save(task);
          this.invoke();
          resolve('success');
          fs.unlink(jsonFilePath, (err) => { });
        });

        // 监听子进程的错误事件
        child.on('error', err => {
          console.error('子进程错误:', err);
          reject(err);
        });
      });
    });
  }

  async executePythonAlgorithm(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();
    return new Promise((resolve, reject) => {
      const exePath = task.algorithm.application;
      const parameters = JSON.parse(task.algorithm.parameters);
      const parametersParsed = this.convertJsonArrayToObject(parameters);
      const { spawn } = require('child_process');
      console.log(JSON.stringify(parametersParsed))
      const pythonProcess = spawn(this.ArcGISPythonURL, [exePath, JSON.stringify(parametersParsed)]);
      pythonProcess.stdout.on('data', (data) => {
        console.log(`stdout: ${data}`);
      });

      pythonProcess.stderr.on('data', (data) => {
        console.error(`stderr: ${data}`);
      });

      pythonProcess.on('close', async (code) => {
        console.log(`child process exited with code ${code}`);
        await this.taskModel.save({
          ...task,
          status: 1,
          progress: 100,
        });
        this.invoke();
        resolve(4000);
      });
    });
  }

  async batchCatalogueByDir(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();
    return new Promise((resolve, reject) => {
      setTimeout(async () => {
        console.log('Done waiting');
        const parameters = JSON.parse(task.algorithm.parameters);
        const parametersParsed = this.convertJsonArrayToObject(parameters);
        console.log(parametersParsed)
        let folderPath = parametersParsed.Dir
        let type = [parametersParsed.fileType]
        // 检查文件夹路径是否存在
        if (!fs.existsSync(folderPath)) {
          return { message: '文件夹不存在' };
        }
        // 读取文件夹中的文件列表
        const files = await fs.promises.readdir(folderPath);
        const fileList: any[] = [];
        for (const file of files) {
          const filePath = path.join(folderPath, file).replace(/\\/g, '/');
          const stats = await fs.promises.stat(filePath);
          // 如果文件不是文件夹，并且文件扩展名在指定类型中，则将其添加到文件列表中
          if (!stats.isDirectory()) {
            if (type.length > 0) {
              type.indexOf(path.extname(file)) !== -1 && fileList.push(filePath);
            }
          }

        }
        let outputFile = parametersParsed.outputFile
        // 返回文件列表
        let Content = { files: fileList, outputFile };

        // 将对象转换为 JSON 字符串
        const jsonContent = JSON.stringify(Content, null, 2);

        // 确保目录存在，如果不存在则创建
        const dir = path.dirname(outputFile);
        if (!fs.existsSync(dir)) {
          fs.mkdirSync(dir, { recursive: true });
        }
        // 将 JSON 字符串写入指定路径的文件
        await fs.promises.writeFile(outputFile, jsonContent, 'utf8');

        await this.taskModel.save({
          ...task,
          status: 1,
          progress: 100,
        });
        this.invoke();
        resolve(4000);
      }, 4000);
    });
  }


  async batchTask(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();

    return new Promise(async (resolve, reject) => {
      const parameters = JSON.parse(task.algorithm.parameters);
      const parametersParsed = this.convertJsonArrayToObject(parameters);
      console.log(parametersParsed)
      const outputType = parametersParsed.outputType;
      const algorithmName = parametersParsed.algorithm;
      const algorithm = await this.AlgorithmModel.findOne({
        where: {
          id: parametersParsed.algorithm,
        },
      });
      console.log(algorithm)

      fs.readFile(parametersParsed.inputFile, 'utf8', async (err, data) => {
        if (err) {
          console.error('Error reading input file:', err);
          return reject(err);
        }

        const jsonContent = JSON.parse(data);
        const files = jsonContent.files;

        const promises = files.map((file, index) => {
          return new Promise((resolve, reject) => {
            const exePath = algorithm.application;
            const { name } = path.parse(file);
            const directoryPath = path.dirname(file);
            const algorithmParameters = JSON.parse(algorithm.parameters);
            let algorithmParametersParsed = this.convertJsonArrayToObject(algorithmParameters);
            algorithmParametersParsed.inputFile = file;
            algorithmParametersParsed.outputFile = `${directoryPath}/${name}${outputType}`;
            const child = childProcess.spawn(exePath, [JSON.stringify(algorithmParametersParsed)]);
            child.stdout.on('data', data => {
              // 处理子进程的标准输出
            });
            child.stderr.on('data', data => {
              console.log(`算法${index}执行完成`);
            });
            child.on('exit', code => {
              resolve(`算法${index}执行完成`);
            });
          });
        });

        try {
          await Promise.all(promises);
          console.log(`算法全部执行完成`);

          await this.taskModel.save({
            ...task,
            status: 1,
            progress: 100,
          });
          this.invoke();
          resolve(4000);
        } catch (error) {
          await this.taskModel.save({
            ...task,
            status: 2,
            progress: 99,
          });
          this.invoke();
          reject(error);
        }
      });

    });
  }

  async generalBatchTask(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();

    return new Promise(async (resolve, reject) => {
      const parameters = JSON.parse(task.algorithm.parameters);
      const parametersParsed = this.convertJsonArrayToObject(parameters);
      const outputDir = parametersParsed.outputDir;
      const outputSuffix = parametersParsed.outputSuffix;
      const outputType = parametersParsed.outputType;
      const algorithmId = parametersParsed.algorithm;
      const runtimeParams = parametersParsed.runtimeParams
      const runtimeParamsParsed = this.convertJsonArrayToObject(runtimeParams);
      const algorithm = await this.AlgorithmModel.findOne({
        where: {
          id: algorithmId,
        },
      });
      console.log(algorithm)

      fs.readFile(parametersParsed.inputFile, 'utf8', async (err, data) => {
        if (err) {
          console.error('Error reading input file:', err);
          return reject(err);
        }
        const jsonContent = JSON.parse(data);
        const files = jsonContent.files;
        const promises = files.map((file, index) => {
          return new Promise((resolve, reject) => {
            const { name } = path.parse(file);
            const exePath = algorithm.application;
            runtimeParamsParsed.inputFile = file;
            runtimeParamsParsed.outputFile = `${outputDir}/${name}${outputSuffix}${outputType}`;
            if (algorithm.executeType == 1) {
              const child = childProcess.spawn(exePath, [JSON.stringify(runtimeParamsParsed)]);
              child.stdout.on('data', data => {
                // 处理子进程的标准输出
              });
              child.stderr.on('data', data => {
                console.log(`算法${index}执行完成`);
              });
              child.on('exit', code => {
                resolve(`算法${index}执行完成`);
              });
            } else {
              const pythonProcess = childProcess.spawn(this.ArcGISPythonURL, [exePath, JSON.stringify(runtimeParamsParsed)]);
              console.log(`算法${index}开始执行`)
              pythonProcess.stdout.on('data', (data) => {
                console.log(`stdout: ${data}`);
              });

              pythonProcess.stderr.on('data', (data) => {
                console.error(`stderr: ${data}`);
              });

              pythonProcess.on('exit', async (code) => {
                console.log(`child process exited with code ${code}`);
                resolve(`算法${index}执行完成`);
              });
            }

          });
        });

        try {
          await Promise.all(promises);
          console.log(`算法全部执行完成`);

          await this.taskModel.save({
            ...task,
            status: 1,
            progress: 100,
          });
          this.invoke();
          resolve(4000);
        } catch (error) {
          await this.taskModel.save({
            ...task,
            status: 2,
            progress: 99,
          });
          this.invoke();
          reject(error);
        }
      });

    });
  }



  async resultBatchPush(task) {
    console.log('========================================')
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();

    return new Promise(async (resolve, reject) => {
      const parameters = JSON.parse(task.algorithm.parameters);
      const parametersParsed = this.convertJsonArrayToObject(parameters);

      fs.readFile(parametersParsed.inputFile, 'utf8', async (err, data) => {
        if (err) {
          console.error('Error reading input file:', err);
          return reject(err);
        }
        const jsonContent = JSON.parse(data);
        const files = jsonContent.files;
        const promises = files.map((file, index) => {
          return new Promise((resolve, reject) => {
            const { name } = path.parse(file);
            const soilEtResult = new SoilEtResult();
            soilEtResult.fileName = name
            soilEtResult.monitorDate = parametersParsed.monitorDate
            soilEtResult.irrigationArea = parametersParsed.irrigationArea
            soilEtResult.resultType = parametersParsed.resultType
            soilEtResult.box = JSON.stringify([parametersParsed.minX, parametersParsed.minY, parametersParsed.maxX, parametersParsed.maxY])
            soilEtResult.filePath = file
            const result = this.SoilEtResultModel.save(soilEtResult)
            if (result) {
              console.log(`成果${index}推送完成`);
            }
          });
        });
        try {
          await Promise.all(promises);
          console.log(`算法全部执行完成`);

          await this.taskModel.save({
            ...task,
            status: 1,
            progress: 100,
          });
          this.invoke();
          resolve(4000);
        } catch (error) {
          await this.taskModel.save({
            ...task,
            status: 2,
            progress: 99,
          });
          this.invoke();
          reject(error);
        }
      });

    });
  }


  async executeLinuxAlgorithm(task) {
    console.log('========================================');
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();

    return new Promise(async (resolve, reject) => {
      const parameters = JSON.parse(task.algorithm.parameters);
      const exePath = task.algorithm.application;

      try {
        const response = await fetch(exePath, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(parameters)  // 参数放在请求体中
        });

        if (response.ok) {
          console.log(`算法执行完成`);
          await this.taskModel.save({
            ...task,
            status: 2,
            progress: 5,
          });
          this.invoke();
          await  setTimeout( ()=>{
             this.taskModel.save({
              ...task,
              status: 1,
              progress: 100,
            });
            this.invoke();
            resolve(4000);
          },60000)
        } else {
          console.error(`算法执行失败:`, response.status);
          await this.taskModel.save({
            ...task,
            status: 2,
            progress: 99,
          });
          this.invoke();
          reject(new Error(`HTTP ${response.status}`));
        }
      } catch (error) {
        console.error(`请求出错:`, error);
        await this.taskModel.save({
          ...task,
          status: 2,
          progress: 99,
        });
        this.invoke();
        reject(error);
      }
    });
}




  async createBatchCatalogue(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();
    return new Promise(async (resolve, reject) => {
      const parameters = JSON.parse(task.algorithm.parameters);
      const parametersParsed = this.convertJsonArrayToObject(parameters);
      console.log(parametersParsed)
      try {
        setTimeout(async () => {
          const { outputFile } = parametersParsed;

          // 将对象转换为 JSON 字符串
          const jsonContent = JSON.stringify(parametersParsed, null, 2);

          // 确保目录存在，如果不存在则创建
          const dir = path.dirname(outputFile);
          if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true });
          }
          // 将 JSON 字符串写入指定路径的文件
          await fs.promises.writeFile(outputFile, jsonContent, 'utf8');
          await this.taskModel.save({
            ...task,
            status: 1,
            progress: 100,
          });
          this.invoke();
          resolve(4000);
        }, 3000)
        // 返回成功消息和 JSON 文件路径
      } catch (error) {
        console.error('Error:', error);
      }
    });
  }
  async pushMPDIResult(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();
    return new Promise((resolve, reject) => {
      setTimeout(async () => {
        const parameters = JSON.parse(task.algorithm.parameters);
        const parametersParsed = this.convertJsonArrayToObject(parameters);
        console.log(parametersParsed)
        const m1Product = new M1Product();
        m1Product.box = JSON.stringify([parametersParsed.minX, parametersParsed.minY, parametersParsed.maxX, parametersParsed.maxY])
        m1Product.productName = parametersParsed.origin_img
        m1Product.step1 = parametersParsed.origin_img
        m1Product.step2 = parametersParsed.after_img
        m1Product.step3 = parametersParsed.MPDI_product
        m1Product.step4 = parametersParsed.soil_water
        m1Product.step5 = parametersParsed.calc
        m1Product.satelliteType = parametersParsed.satelliteType
        m1Product.produceDate = parametersParsed.produceDate
        this.M1ProductModel.save(m1Product)
        await this.taskModel.save({
          ...task,
          status: 1,
          progress: 100,
        });
        this.invoke();
        resolve(4000);
      }, 0);
    });
  }

  async previewResult(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();
    return new Promise((resolve, reject) => {
      setTimeout(async () => {
        console.log('Done waiting');
        await this.taskModel.save({
          ...task,
          status: 1,
          progress: 100,
        });
        this.invoke();
        resolve(4000);
      }, 4000);
    });
  }



  async bindStyleToLayer(task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();
    // GeoServer 的认证信息，如果不需要认证，可以将这部分省略
    const username = 'admin';
    const password = 'geoserver';

    // 构造认证信息
    const auth = `${username}:${password}`;
    const geoserverUrl = task.algorithm.application; // GeoServer 的 URL
    const workspace = 'result'; // 工作区名称
    const parameters = JSON.parse(task.algorithm.parameters);
    let parsedParams = this.convertJsonArrayToObject(parameters);
    const layerName = parsedParams.layer_name;
    const styleName = parsedParams.style_name;
    const data = {
      layer: {
        defaultStyle: {
          name: styleName,
        },
      },
    };

    try {
      // 发送 PUT 请求将样式应用到图层
      let response = await axios.put(
        `${geoserverUrl}/geoserver/rest/layers/${workspace}:${layerName}`,
        data,
        {
          headers: {
            'Content-Type': 'application/json',
            Authorization: `Basic ${Buffer.from(auth).toString('base64')}`,
          },
        }
      );
      await this.taskModel.save({
        ...task,
        status: 1,
        progress: 100,
      });
      this.invoke();
    } catch (error) {
      console.error('图层样式绑定失败', error);
    }
  }

  async publishShpFile(task: Task) {
    await this.taskModel.save({
      ...task,
      status: 2,
      progress: 50,
    });
    this.invoke();
    const parameters = JSON.parse(task.algorithm.parameters);
    let parsedParams = this.convertJsonArrayToObject(parameters);
    const shpPath = parsedParams.shp_path;
    let { name, dir } = path.parse(shpPath);
    const shpZipFile = `${dir}/${name}_shp.zip`;
    setTimeout(async () => {
      return await this.compressShpToZip(shpPath, shpZipFile, task, name);
    }, 1000);
  }

  async compressShpToZip(
    shpFilePath: string,
    outputZipPath: string,
    task: Task,
    shpName: string
  ) {
    const self = this;
    return new Promise(async (resolve, reject) => {
      // 创建一个输出流到指定的 ZIP 文件
      const output = fs.createWriteStream(outputZipPath);
      const archive = archiver('zip', {
        zlib: { level: 9 }, // 设置压缩级别
      });

      // 监听错误事件
      output.on('error', function (err) {
        reject(err);
      });

      // 监听关闭事件
      output.on('close', async function () {
        console.log(archive.pointer() + ' total bytes');
        let result = await self.publishShpToGeoServer(
          outputZipPath,
          task,
          shpName
        );
        resolve(result);
      });

      // 绑定输出流到压缩程序
      archive.pipe(output);

      // 获取文件名
      const shpFileName = shpFilePath.split('/').pop().replace('.shp', '');
      // 将与 .shp 文件同名的文件（除了 .zip 文件）添加到压缩程序
      const shpFileDir = path.dirname(shpFilePath);
      return await fs.readdir(shpFileDir, async (err, files) => {
        if (err) {
          reject(err);
        } else {
          files.forEach(file => {
            if (
              (file.startsWith(shpFileName) && file.endsWith('.shx')) ||
              file.endsWith('.dbf') ||
              file.endsWith('.shp') ||
              file.endsWith('.prj')
            ) {
              console.log(file);
              const filePath = path.join(shpFileDir, file);
              /* const fileParts = file.split('.');
              const newFileName =fileParts[0] + '_shp.' + fileParts.slice(1).join('.'); // 在文件名末尾添加 "_shp" */
              const pathObj = path.parse(file);
              const newFileName = pathObj.name + '_shp' + pathObj.ext;
              archive.file(filePath, { name: newFileName });
            }
          });

          // 完成压缩
          await archive.finalize();
        }
      });
    });
  }

  private async publishShpToGeoServer(
    shpFilePath: string,
    task: Task,
    shpName: string
  ) {
    try {
      const workspace = 'result';
      const layerName = shpName + '_shp';

      // GeoServer 的认证信息，如果不需要认证，可以将这部分省略
      const username = 'admin';
      const password = 'geoserver';

      const restUrl = `${task.algorithm.application}/geoserver/rest/workspaces/${workspace}/datastores/${layerName}/file.shp`;

      // 构造认证信息
      const auth = `${username}:${password}`;

      const fileData = await fs.promises.readFile(shpFilePath);

      const response = await axios.put(restUrl, fileData, {
        headers: {
          'Content-Type': 'application/zip',
          Authorization: `Basic ${Buffer.from(auth).toString('base64')}`,
        },
      });

      console.log('Shapefile 成功发布到 GeoServer!');
      await this.taskModel.save({
        ...task,
        status: 1,
        progress: 100,
      });
      this.invoke();
      return {
        success: true,
        data: task,
        message: '成功发布',
      };
    } catch (error) {
      console.error('发布失败:', error.message);
      return {
        success: false,
        data: error.message,
        message: '发布失败',
      };
    }
  }

  public async publishTifToGeoServer(task: Task) {
    try {
      task.status = 2;
      this.taskModel.save(task);
      this.invoke();
      const workspace = 'result';
      // const tifFilePath = this.dataBaseURL + task.inputFile;
      const parameters = JSON.parse(task.algorithm.parameters);
      let parsedParams = this.convertJsonArrayToObject(parameters);
      const tifFilePath = parsedParams.image_path;
      let { name } = path.parse(tifFilePath);
      const layerName = name;
      // GeoServer 的认证信息，如果不需要认证，可以将这部分省略
      const username = 'admin';
      const password = 'geoserver';
      const restUrl = `${task.algorithm.application}/geoserver/rest/workspaces/${workspace}/coveragestores/${layerName}/file.geotiff`;

      // 构造认证信息
      const auth = `${username}:${password}`;
      const fileData = await fs.promises.readFile(tifFilePath);
      const response = await axios.put(restUrl, fileData, {
        headers: {
          'Content-Type': 'image/tiff',
          Authorization: `Basic ${Buffer.from(auth).toString('base64')}`,
        },
      });
      if (response) {
        task.status = 1;
        task.progress = 100;
        this.taskModel.save(task);
        this.invoke();
        console.log(response);
      }
      return {
        success: true,
        data: {
          taskId: task.id,
        },
        message: 'TIFF 文件成功发布到 GeoServer!',
      };
    } catch (error) {
      console.error('发布失败:', error.message);
    }
  }

  async getTaskList(params: Ipage) {
    const [result, total] = await this.taskModel.findAndCount({
      where: { name: Like(`%${params.keyword ? params.keyword : ''}%`) },
      skip: (params.page_index - 1) * params.page_size,
      take: params.page_size,
      order: { createDate: 'DESC' },
    });
    return {
      succes: true,
      data: result,
      total,
      message: '成功',
    };
  }

  async deleteTask(id: number) {
    const task = await this.taskModel.findOne({
      where: {
        id,
      },
    });
    if (!task) {
      return {
        succes: false,
        message: '未查询到要删除的数据',
      };
    }

    // 删除单个
    let result = await this.taskModel.remove(task);
    return {
      succes: true,
      data: result.id,
      message: '成功',
    };
  }
  async getTaskById(id: number) {
    const task = await this.taskModel.findOne({
      where: {
        id,
      },
    });
    if (!task) {
      return {
        succes: false,
        message: '未查询到要找的数据',
      };
    }

    return {
      succes: true,
      data: task,
      message: '成功',
    };
  }

  async changeStatus(id: number, status: number) {
    try {
      const task = await this.taskModel.findOneOrFail({
        where: { id },
        relations: ['algorithm'],
      });

      task.status = status;
      const updatedTask = await this.taskModel.save(task);
      return {
        success: true,
        data: {
          id: updatedTask.id,
          status: updatedTask.status,
        },
        message: '任务状态更新成功',
      };
    } catch (error) {
      return {
        success: false,
        message: '任务状态更新失败',
      };
    }
  }

  async executeTaskByStatus() {
    const results = await this.taskModel.find({
      where: { status: 0 },
      take: 1,
      relations: ['algorithm'],
    });
    if (results.length > 0) {
      console.log('已检索到待执行的同步task')
      results.map(async task => {
        let algorithm = task.algorithm
        const runTask = await this.taskModel.findOne({
          where: [
            { algorithm: { id: algorithm.id }, status: 2 }
          ],
        });
        if (runTask) {
          console.log('有运行的同类型同步task,继续等待执行')
        } else {
          console.log('没有运行的同类型同步task,开始执行')
          await this.executeSwitch(task);
        }
      });
    } else {
      console.log('没有待执行的同步task')
    }
  }


  async executeProcessTaskByStatus() {
    // 检查是否有状态为 2 且 allowAsync 为 false 的任务
    const runningTasks = await this.taskModel.find({
      where: { status: 2, allowAsync: false },
    });

    if (runningTasks.length > 0) {
      console.log("当前有状态为 '执行中' 且 allowAsync 为 false 的任务，跳过执行");
      return;
    }

    // 如果没有符合条件的执行中任务，查找状态为 0、类型为 2、并且允许异步执行为 false 的任务
    const results = await this.taskModel.find({
      where: { status: 0, type: 2, allowAsync: false },
      take: 1,
      relations: ['algorithm'],
    });

    if (results.length > 0) {
      console.log("已检索到待执行的同步流程task");
      await this.GraphService.executeGraphByTask(results[0].graphId, results[0].id);
    } else {
      console.log("没有待执行的同步流程task");
    }
  }



  // 保存日志的函数
  private async saveLog(task: Task, logContent: string, append: boolean = true) {
    try {
      if (append && task.log) {
        task.log += logContent;
      } else {
        task.log = logContent;
      }
      await this.taskModel.save(task);
    } catch (error) {
      console.error('保存日志失败:', error);
    }
  }

  // 添加时间戳到日志的辅助函数
  private formatLogWithTimestamp(message: string): string {
    const timestamp = new Date().toISOString();
    return `[${timestamp}] ${message}\n`;
  }

  async executeAlgorithm(task: Task) {
    task.status = 2;
    await this.taskModel.save(task);
    this.invoke();

    const exePath = task.algorithm.application;
    let parameters;

    if (task.parameters) {
      parameters = JSON.parse(task.parameters);
    } else {
      parameters = JSON.parse(task.algorithm.parameters);
    }

    const parametersParsed = this.convertJsonArrayToObject(parameters);
    const jsonParameter = JSON.stringify(parametersParsed);

    // 记录执行命令到日志
    const executeCommand = `${exePath} ${jsonParameter}`;
    console.log(executeCommand);

    // 保存执行命令到日志
    const commandLog = this.formatLogWithTimestamp(`执行命令: ${executeCommand}`);
    await this.saveLog(task, commandLog, false); // 第一次保存，不追加

    // 使用child_process.spawn执行exe程序
    const child = childProcess.spawn(exePath, [jsonParameter]);
    let logOutput = ''; // 用于临时保存日志信息

    // 监听子进程的标准输出
    child.stdout.on('data', async (data) => {
      const logData = data.toString('utf-8');
      logOutput += logData;

      // 实时保存标准输出日志
      const formattedLog = this.formatLogWithTimestamp(`[STDOUT] ${logData.trim()}`);
      await this.saveLog(task, formattedLog, true);

      // 提取进度信息
      let progress = this.extractNumberFromString(logData);
      if (progress) {
        task.progress = progress;
        await this.taskModel.save(task);
        this.invoke();
      }
    });

    // 监听子进程的标准错误输出
    child.stderr.on('data', async (data) => {
      const errorData = data.toString('utf-8');
      logOutput += errorData;
      console.log(errorData);

      // 保存错误日志
      const formattedErrorLog = this.formatLogWithTimestamp(`[STDERR] ${errorData.trim()}`);
      await this.saveLog(task, formattedErrorLog, true);
    });

    // 监听进程退出
    child.on('exit', async (code) => {
      console.log('算法执行完成');

      // 保存进程退出日志
      const exitLog = this.formatLogWithTimestamp(`进程退出，退出码: ${code}`);
      await this.saveLog(task, exitLog, true);

      task.status = 1;
      task.progress = 100;
      await this.taskModel.save(task);
      this.invoke();

      switch (task.algorithm.id) {
        case 135:
          this.simulationBeijig(parametersParsed.outputFile);
          break;
        case 136:
          this.previewBeijig(parametersParsed.outputFile);
          break;
        default:
          break;
      }
    });

    // 监听进程错误
    child.on('error', async (error) => {
      console.error('进程启动失败:', error);

      // 保存进程错误日志
      const processErrorLog = this.formatLogWithTimestamp(`进程启动失败: ${error.message}`);
      await this.saveLog(task, processErrorLog, true);

      task.status = -1; // 可以定义一个错误状态
      await this.taskModel.save(task);
      this.invoke();
    });

    return {
      success: true,
      data: {
        taskId: task.id,
      },
      message: '任务执行成功',
    };
  }

  extractNumberFromString(str: string): number | null {
    console.log(str)
    const regex = /(\d+)%/;
    const match = str.match(regex);
    let percentage = null;
    if (match) {
      percentage = parseInt(match[1]);
      return percentage;
    }
    return null; // 如果没有找到数字或字符串不符合格式，则返回 null
  }
  async invoke() {
    this.wsApp.clients.forEach(ws => {
      const message = { cmd: 'task', action: 'refresh' };
      ws.send(JSON.stringify(message));
    });
  }

  private convertJsonArrayToObject(jsonArray) {
    return jsonArray.reduce((result, item) => {
      result[item.param_name] = item.default_value;
      return result;
    }, {});
  }

  changeListenStatus(status: boolean) {
    if (status) {
      this.syncJob.start();
      return {
        success: false,
        message: '开启自动处理监听',
      };
    } else {
      this.syncJob.stop();
      return {
        success: false,
        message: '停止自动处理监听',
      };
    }
  }

  async simulationBeijig(outputFile: string) {
    try {
      // 读取文件内容
      const fileContent = fs.readFileSync(outputFile, 'utf-8');

      // 解析 JSON
      const jsonData = JSON.parse(fileContent);

      const originalTimestamp = new Date(jsonData.resultTimestamp);

      // 自定义格式化时间为 YYYY-MM-DD HH:mm:ss
      const formattedTimestamp = `${originalTimestamp.getFullYear()}-${(originalTimestamp.getMonth() + 1).toString().padStart(2, '0')}-${originalTimestamp.getDate().toString().padStart(2, '0')} ${originalTimestamp.getHours().toString().padStart(2, '0')}:${originalTimestamp.getMinutes().toString().padStart(2, '0')}:${originalTimestamp.getSeconds().toString().padStart(2, '0')}`;

      // 修改 jsonData 中的 resultTimestamp
      jsonData.resultTimestamp = formattedTimestamp;
      const taskId = jsonData.taskId
      const TM = formattedTimestamp
      const shp_dir = 'BJ_' + jsonData.taskId
      const shpFullDir = 'D:/01北京城市内涝模型/3系统模拟结果/' + shp_dir
      this.processShpFile(shpFullDir, taskId, TM)
      // 准备请求地址
      const url = `${this.renbaoBaseURL}/api/misc/riskcat/imitate/out/receiveTaskData`;

      // 发送 POST 请求
      const response = await axios.post(url, jsonData, {
        headers: {
          'Content-Type': 'application/json',  // 设置请求头为 JSON 类型
        },
      });
      // 打印响应结果
      console.log('Response:', response.data);
    } catch (error) {
      // 捕获并处理错误
      console.error('Error:', error.message);
    }
  }

  async previewBeijig(outputFile: string) {
    try {
      // 读取文件内容
      const fileContent = fs.readFileSync(outputFile, 'utf-8');

      // 解析 JSON
      const jsonData = JSON.parse(fileContent);




      const originalTimestamp = new Date(jsonData.resultTimestamp);

      // 自定义格式化时间为 YYYY-MM-DD HH:mm:ss
      const formattedTimestamp = `${originalTimestamp.getFullYear()}-${(originalTimestamp.getMonth() + 1).toString().padStart(2, '0')}-${originalTimestamp.getDate().toString().padStart(2, '0')} ${originalTimestamp.getHours().toString().padStart(2, '0')}:${originalTimestamp.getMinutes().toString().padStart(2, '0')}:${originalTimestamp.getSeconds().toString().padStart(2, '0')}`;

      // 修改 jsonData 中的 resultTimestamp
      jsonData.resultTimestamp = formattedTimestamp;

      const taskId = jsonData.taskId
      const TM = formattedTimestamp
      const shp_dir = 'BJ_' + jsonData.taskId
      const shpFullDir = 'D:/01北京城市内涝模型/3系统模拟结果/' + shp_dir

      this.processShpFile(shpFullDir, taskId, TM)

      // 准备请求地址
      const url = `${this.renbaoBaseURL}/api/misc/riskcat/disaster/out/receiveBeiJingWarning`;

      // 发送 POST 请求
      const response = await axios.post(url, [jsonData], {
        headers: {
          'Content-Type': 'application/json',  // 设置请求头为 JSON 类型
        },
      });
      await fs1.writeFile(outputFile, JSON.stringify([jsonData]));
      // 打印响应结果
      console.log('Response:', response.data);
    } catch (error) {
      // 捕获并处理错误
      console.error('Error:', error.message);
    }
  }

  async processShpFile(shpFullDir: string, taskId: string, TM: string) {
    const requiredFiles = [
      "01积水淹没区.dbf",
      "01积水淹没区.shp",
      "01积水淹没区.shx"
    ];

    const targetDir = path.join("D:/01北京城市内涝模型/7_矢量数据转换", taskId, "01_origin");

    try {
      // 检查目标目录是否存在，如果不存在则创建
      if (!fs.existsSync(targetDir)) {
        fs.mkdirSync(targetDir, { recursive: true });
      }

      const missingFiles = requiredFiles.filter(file => {
        const filePath = path.join(shpFullDir, file);
        return !fs.existsSync(filePath);
      });

      if (missingFiles.length > 0) {
        console.log(`以下文件缺失: ${missingFiles.join(', ')}`);
        return false;
      } else {
        console.log("所有文件均已存在，正在复制文件...");

        // 复制文件到目标路径
        requiredFiles.forEach(file => {
          const sourcePath = path.join(shpFullDir, file);
          const destinationPath = path.join(targetDir, file);
          fs.copyFileSync(sourcePath, destinationPath);
          console.log(`${file} 已复制到目标路径`);
        });

        console.log("所有文件均已成功复制，可以继续处理任务。");
        this.GraphService.executeGraphByDynamic3(339, taskId, TM)
        return true;
      }
    } catch (error) {
      console.error("文件检查或复制过程中出错:", error);
      return false;
    }
  }

}
